package com.atguigu.gmall.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;

import com.atguigu.gmall.common.util.IpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;
@Component
public class AuthGlobalFilter implements GlobalFilter {

    // 创建一个对象，匹配路径的工具类
    private AntPathMatcher antPathMatcher = new AntPathMatcher();
    @Value("${authUrls.url}")
    private String authUrls;//url= trade.html,myOrder.html ,list.html #, addCart.html # 用户访问该控制器的时候，会被拦截跳转到登录！

    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 网关鉴权，过滤器
     * @param exchange
     * @param chain
     * @return
     */
    @Override//chain过滤器链，
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {



        ServerHttpRequest request = exchange.getRequest();
        // 获取Url
        String path = request.getURI().getPath();
        // 如果是内部接口，则网关拦截不允许外部访问！
        if (antPathMatcher.match("/**/inner/**",path)){
            //如果匹配成功，则不能访问这样的路径
            ServerHttpResponse response = exchange.getResponse();

            //提示
            return out(response, ResultCodeEnum.PERMISSION);
    }

        // 获取用户Id
        String userId = getUserId(request);
        String userTempId = getUserTempId(request);
        if("-1".equals(userId)) {
            //获取响应对象
            ServerHttpResponse response = exchange.getResponse();
            //提示
            return out(response, ResultCodeEnum.PERMISSION);
        }

        if (antPathMatcher.match("/api/**/auth/**",path)){
            //判断用户id不能为空
            if (StringUtils.isEmpty(userId)){
                //如果id为空，提示响应登录
                ServerHttpResponse response = exchange.getResponse();
                return out(response,ResultCodeEnum.LOGIN_AUTH);//未登录
            }
        }
        String[] split = authUrls.split(",");
        for (String url : split) {
            if (path.indexOf(url)!=-1&&StringUtils.isEmpty(userId)){
                //设置跳转到登录页面
                ServerHttpResponse response = exchange.getResponse();
                response.setStatusCode(HttpStatus.SEE_OTHER);//303
                response.getHeaders().set(HttpHeaders.LOCATION,"http://www.gmall.com/login.html?originUrl="+request.getURI());
                // 重定向到登录
                return response.setComplete();

            }
            // 将userId 传递给后端
            if (!StringUtils.isEmpty(userId) ||!StringUtils.isEmpty(userTempId)){
                if(!StringUtils.isEmpty(userId)) {
                    request.mutate().header("userId", userId).build();
                }
                if(!StringUtils.isEmpty(userTempId)) {
                    request.mutate().header("userTempId", userTempId).build();
                }

                // 将现在的request 变成 exchange对象
                return chain.filter(exchange.mutate().request(request).build());
            }

        }
        return chain.filter(exchange);
    }

    /**
     * 获取当前用户临时用户id
     * @param request
     * @return
     */
    private String getUserTempId(ServerHttpRequest request){
        String userTempId = "";
        HttpCookie httpCookie = request.getCookies().getFirst("userTempId");
        if (httpCookie!=null){
            userTempId = httpCookie.getValue();
        }else {
            List<String> list = request.getHeaders().get("userTempId");
            if (list!=null){
                userTempId = list.get(0);
            }
        }
        return userTempId;
    }
    /**
     * 获取用户id
     * @param request
     * @return
     */
    private String getUserId(ServerHttpRequest request) {

        String token = "";
        //先从cookies中获取token
        HttpCookie first = request.getCookies().getFirst("token");
        if (first!=null){
            token = first.getValue();
        }else {
            //如果没有，就从headers中获取
            List<String> list = request.getHeaders().get("token");
            if (!StringUtils.isEmpty(list)){
                token = list.get(0);
            }
        }


        //  获取到token了,如果下面的都一致，返回用户id，不一致，返回-1；
        if (!StringUtils.isEmpty(token)) {
            //  组成缓存组成的key！ String userLoginKey = RedisConst.USER_LOGIN_KEY_PREFIX + token;
            String userLoginKey = "user:login:" + token;
//            Boolean flag = redisTemplate.hasKey(userLoginKey);
//            if(!flag){
//                return null;
//            }
            //从缓存中获取数据
            String strJson = (String) redisTemplate.opsForValue().get(userLoginKey);
            //  这个字符串的本质：JSONObject
            JSONObject jsonObject = JSON.parseObject(strJson, JSONObject.class);
            //  先获取ip 地址
            String ip = (String) jsonObject.get("ip");
            if (ip.equals(IpUtil.getGatwayIpAddress(request))){
                //  获取到userId
                String userId = (String) jsonObject.get("userId");
                //  返回用户Id
                return userId;
            }else {
                return "-1";
            }

        }
        return null;
    }

    /**
     * 提示一下拒绝方法
     * @param response
     * @param permission
     * @return
     */
    private Mono<Void> out(ServerHttpResponse response, ResultCodeEnum permission) {
        Result<Object> result = Result.build(null, permission);
        String string = JSON.toJSONString(result);
        DataBuffer wrap = response.bufferFactory().wrap(string.getBytes());
        response.getHeaders().add("Content-Type","application/json;charset=UTF-8");
        return response.writeWith(Mono.just(wrap));
    }
}
